/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.etherframework.behaviour
{
	import org.etherframework.behaviour.rules.IRules;
	import org.etherframework.behaviour.rules.Rules;
	import org.etherframework.behaviour.rules.core.IChain;
	import org.etherframework.behaviour.rules.core.IControl;
	import org.etherframework.behaviour.rules.events.FeedbackEvent;
	import org.etherframework.core.Access;
	import org.etherframework.core.DomainAccess;
	import org.etherframework.core.IBridge;
	import org.etherframework.core.IControllerPart;
	import org.etherframework.core.ether_internal;
	import org.etherframework.core.events.DataEvent;
	import org.etherframework.core.events.InteractionEvent;
	
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	
	import mx.core.EventPriority;
	import mx.utils.UIDUtil;
	
	[ExcludeClass]
	public class BehaviourController implements IControllerPart
	{
		private var eventPriority:int;
		
		private var isInitialized:Boolean = false;
		
		public function BehaviourController(tags:Array)
		{
			_tags = tags;
			eventPriority = EventPriority.CURSOR_MANAGEMENT;
		}
		
		public function initialize():void
		{
			if (isInitialized && !_bridge)
				return;
			
			var j:int;
			var tagsLen:int = _tags.length;
			var tag:Behaviour;
			var workspacesLen:int;
			var workspace:IRules;
			
			var dispatcher:IEventDispatcher;
			
			_workspaces = [];
			
			for (var i:int = 0; i < tagsLen; ++i)
			{
				tag = _tags[i];
				_workspaces = tag.items;
				workspacesLen = _workspaces.length;
				
				for (j = 0; j < workspacesLen; ++j)
				{
					workspace = _workspaces[j];
					dispatcher = new BehaviourDispatcher(workspace, bridge, workspace.access, workspace.domain);
					workspace.addEventListener("flow", workspaceFlowHandler);
					workspace.dispatcher = dispatcher;
					IControl(workspace).initialize();
					wireWorkspace(workspace);
				}
			}
			
			isInitialized = true;
		}
		
		public function uninitialize():void
		{
			if (!isInitialized)
				return;
			
			var workspaceLen:int = _workspaces.length;
			var workspace:IRules;
			
			for (var i:int = 0; i < workspaceLen; ++i)
			{
				workspace = _workspaces[i];
				bridge.removeWire(workspace);
				BehaviourDispatcher(workspace.dispatcher).removeAllEventListeners();
			}
			
			isInitialized = false;
		}
		
		public function addItem(value:Object):Object
		{
			return null;
		}
		
		public function removeItem(value:Object):Object
		{
			return null;	
		}
		
		public function getItem(value:*):*
		{
			return null;
		}
		
		private var _tags:Array = [];
		
		public function get tags():Array
		{
			return _tags;
		}
		
		private var _workspaces:Array;
		
		public function get workspaces():Array
		{
			return _workspaces;
		}
		
		private var _bridge:IBridge;
		
		public function get bridge():IBridge
		{
			return _bridge;
		}
		
		public function set bridge(value:IBridge):void
		{
			_bridge = value;
		}
		
		private function wireWorkspace(workspace:IRules):void
		{
			bridge.addWire(workspace);
			wireControls(Rules(workspace).ether_internal::children);
			workspace.dispatchEvent(new Event("ready"));
		}
		
		private function wireControls(items:Array):void
		{
			var itemsLen:int = items.length;
			var item:IControl;
			
			for (var i:int = 0; i < itemsLen; ++i)
			{
				item = items[i];
				bridge.addWire(item);
				
				if (item is IChain)
				{
					wireControls(IChain(item).children);
				}
			}
		}
		
		// FIXME:
		private function workspaceFlowHandler(event:DataEvent):void
		{
			var feedbackEvent:FeedbackEvent = event.data[0];
			var chain:Array = event.data[1];
			var shortRawType:String = (chain.length > 1) ? chain.slice(-2).join(".") : "";
			var rawType:String = (event.data[2] || feedbackEvent.context.source.reason.kind) + "." + chain.join(".");
			var initiatorId:String = UIDUtil.getUID(feedbackEvent.context.source.initiator);
			var shortType:String = (shortRawType) ?  InteractionEvent.FEEDBACK + shortRawType : "";
			var type:String = InteractionEvent.FEEDBACK + rawType;
			var strictShortType:String = (shortRawType) ?  InteractionEvent.FEEDBACK + initiatorId + shortRawType : "";
			var strictType:String = InteractionEvent.FEEDBACK + initiatorId + rawType;
			var access:String = event.currentTarget.access;
			var domain:String = event.currentTarget.domain;
			
			if (strictShortType)
			{
				dispatchFeedback(strictShortType, feedbackEvent, 
					access, domain);
				
				if (feedbackEvent.isDefaultPrevented())
					return;
			}
			
			if (strictType)
			{
				dispatchFeedback(strictType, feedbackEvent, 
					access, domain);
				
				if (feedbackEvent.isDefaultPrevented())
					return;
			}
			
			if (shortType)
			{
				dispatchFeedback(shortType, feedbackEvent, 
					access, domain);
				
				if (feedbackEvent.isDefaultPrevented())
					return;
			}
			
			dispatchFeedback(type, feedbackEvent, 
				access, domain);
		}
		
		private function dispatchFeedback(type:String, event:FeedbackEvent, access:String, domain:String):void
		{
			if (type)
			{
				var evt:DataEvent = new DataEvent(type);
				evt.data = event;
				bridge.dispatch(evt, access, domain);
			}
		}
		
	}
}